/*
 * @Author: your name
 * @Date: 2021-09-14 15:01:34
 * @LastEditTime: 2021-09-15 17:00:05
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \bigdate\src\ntils\loginfo.js
 */
import {
    LogType,
    initiatorType,
    Resource,
    ResourceError,
    EventTargets,
    JsError,
} from './typs'

// 系统时间
let pertime = performance.timing
// 统计页面加载时间
const openTime = pertime.navigationStart
// 统计时的时间
const nowTime = new Date().getTime()
// 总信息
let logInfo:LogType = {}
window.onload = function () {
    // 为了获取性能的时候不影响到浏览器 设置在浏览器空闲时间获取性能及资源信息 requestIdleCallback
    if (window.requestIdleCallback) {
        window.requestIdleCallback(() => {
            getLoginfo()
            getResources()
        })
    } else {
        getLoginfo()
        getResources()
    }
}

function getLoginfo() {
    let { domLoading, domComplete, loadEventEnd, responseEnd, requestStart } = pertime
    // 请求耗时
    const requestTime = responseEnd - requestStart
    // 页面加载耗时
    const allloadTime = +(new Date()) - openTime
    // DOM 渲染耗时
    const domTime = domComplete - domLoading  
    // 白屏耗时
    const whiteScreenTime = +new Date() - openTime
    // 获取系统名称
    const mobile = mobileType()
    logInfo = {
        openTime,
        domTime,
        whiteScreenTime,
        allloadTime,
        requestTime,
        nowTime,
        mobile,
    }
}

/** 获取浏览器内核
 * @description: 
 * @param {*}
 * @return {*}
 */

function mobileType() {
    let u = navigator.userAgent, app = navigator.appVersion
    let type = { // 移动终端浏览器版本信息
        ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端
        iPad: u.indexOf('iPad') > -1, // 是否iPad
        android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, // android终端或者uc浏览器
        iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, // 是否为iPhone或者QQHD浏览器
        trident: u.indexOf('Trident') > -1, // IE内核
        presto: u.indexOf('Presto') > -1, // opera内核
        webKit: u.indexOf('AppleWebKit') > -1, // 苹果、谷歌内核
        gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, // 火狐内核
        mobile: !!u.match(/AppleWebKit.*Mobile/i) || !!u.match(/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/), // 是否为移动终端
        webApp: u.indexOf('Safari') == -1, // 是否web应该程序，没有头部与底部
    }
    let lists = Object.keys(type)
    for (let i = 0; i < lists.length; i++) {
        if (type[lists[i]]) {
            return lists[i]
        }
    }  
}

// 获取资源信息
/**
 * 
 * @returns 主要解决 资源过大，网速过慢，Dom元素过多
 */
const resource:Resource = {
    xmlhttprequest: [],
    css: [],
    other: [],
    script: [],
    img: [],
    link: [],
    fetch: [],
}
function getResources() {
    if (!window.performance) return
    const data = window.performance.getEntriesByType('resource')
    
    data.forEach((item) => {
        const array = resource[item.initiatorType]
        array && array.push({
            // 资源的名称
            name: item.name,
            // 资源加载耗时
            duration: item.duration.toFixed(2),
            // 资源大小
            size: item.transferSize,
            // 资源所用协议
            protocol: item.nextHopProtocol,
        })
    })
}
/**
 * @description: 文件路径错误，js执行错误
 * @param {*} 资源加载错误 直接通过addEventListener 就可以捕获
 * @return {*}
 */
let fileError:ResourceError = []
addEventListener('error', (e: Event) => {
    const target = e.target as EventTargets
    const arr:ResourceError[] = []
    arr.push({
        type: target.localName,
        url: target.src || target.href,
        msg: (target.src || target.href),
        time: new Date().getTime(),
    }) 
    fileError = arr
    // 直接写入接口及时上报
}, true)
/**
 * @description: 监听js执行错误,因为项目使用ts 可能 监听不准确,只有手动触发js错误才会被监控
 * @param {*} msg
 * @param {*} url
 * @param {*} row
 * @param {*} col
 * @param {*} error
 * @return {*}
 */
let jsError:JsError<String>[] = [] 
window.onerror = function (msg, url, row, col, error) {
    jsError.push(
        {
            type: 'javascript',
            row,
            col,
            msg: error && error.stack ? error.stack : msg,
            url,
            time: new Date().getTime(),
        },
    )
    // 直接写入接口及时上报
    // console.log(jsError);      
}

function proInfos() {
    return {
        fileError,
        jsError,
        resource, 
    }
}

setTimeout(() => {
    window.sessionStorage.setItem('infos', JSON.stringify(logInfo))
}, 1000)

// 所有 配置需要等带onload 执行完毕 执行

export const proInfodata = proInfos()